import Cesium from '../Ces/Cesium'
import WeUniform from './WeUniform'
import WeDisplayShaders from './WeDisplayShaders';

class WeDisplayValueDecoder {
  private _weUniform
  private _isSampler3D = false
  constructor(options) {
    const valueAndColorRamp = options.valueAndColorRamp;
    let { minValue, maxValue, valueRange } = options;

    const floatUniformExt = options.floatUniform || {};

    if (Cesium.defined(valueRange)) {
      // minValue = options.valueRange[0];
      // maxValue = options.valueRange[1];

      floatUniformExt.scale = valueRange[1] - valueRange[0]
      floatUniformExt.offset = valueRange[0]
    }
    if (!minValue && !maxValue
      && Cesium.defined(valueAndColorRamp) && Cesium.defined(valueAndColorRamp.ValueRamp)) {
      const valueRamp = valueAndColorRamp.ValueRamp;

      minValue = valueRamp[0];
      maxValue = valueRamp[valueRamp.length - 1];
    } else {
      minValue = 0.0;
      maxValue = 1.0;
    }

    const floatUniform = {
      minValue,
      maxValue,
      offset: options.offset ?? 0.0,
      scale: options.scale ?? 1.0,
      isUV: options.isUV ? 1.0 : 0.0,
      isCR: 1.0,
      ...floatUniformExt
    };

    this._weUniform = new WeUniform({ floatUniform, name: 'WeDisplayValueDecoder' });
    this.isCR = options.isCR ?? false
  }

  pushDefines(defines) {
    if (this.isSampler3D) {
      defines.push(WeDisplayShaders.WeDefineIsSampler3D)
    }
  }

  get offset() {
    return this._weUniform.Properties.offset
  }

  get scale() {
    return this._weUniform.Properties.scale
  }

  get isSampler3D() {
    return this._isSampler3D;
  }
  set isSampler3D(value) {
    this._isSampler3D = value;
  }
  get minValue() {
    return this._weUniform.Properties.minValue;
  }
  set minValue(value) {
    this._weUniform.Properties.minValue = value;
  }
  get maxValue() {
    return this._weUniform.Properties.maxValue;
  }
  set maxValue(value) {
    this._weUniform.Properties.maxValue = value;
  }
  get isUV() {
    return this.weUniform.Properties.isUV > 0.0
  }
  get isCR() {
    return this.weUniform.Properties.isCR === 1.0
  }
  set isCR(value) {
    this.weUniform.Properties.isCR = value ? 1.0 : 0.0
  }
  get weUniform() {
    return this._weUniform;
  }

  generateDecodeFunc(pixelFormat, pixelDatatype, hasAnimation) {
    const isUV = this.isUV
    const isSampler3D = this.isSampler3D

    let decodeShaderSource = ''
    const WeDecodeValue = `
            vec4 WeDecodeComponent(vec3 str){
                vec3 uvt = str;
                float paddingEast = 1.0 - Weget_paddingEast();
                uvt.x *= paddingEast;

                vec4 comp = WeDecodeVal(u_BaseTexture, uvt);

                ${hasAnimation ? `
                bool shouldAnime = Weget_shouldAnime() > 0.0;
                if (shouldAnime) {
                    float animeStep = Weget_animeStep();
                    vec4 lastComp = WeDecodeVal(u_LastBaseTexture, uvt);
                    comp = mix(lastComp, comp, animeStep);
                }
                ` : ''}

                return comp;
            }

            vec4 WeDecodeComponent(vec2 st){
                vec2 uv = st;
                float paddingEast = 1.0 - Weget_paddingEast();
                uv.x *= paddingEast;

                vec4 comp = WeDecodeVal(u_BaseTexture, uv);

              ${hasAnimation ? `
                bool shouldAnime = Weget_shouldAnime() > 0.0;
                if (shouldAnime) {
                    float animeStep = Weget_animeStep();
                    vec4 lastComp = WeDecodeVal(u_LastBaseTexture, uv);
                    comp = mix(lastComp, comp, animeStep);
                }
                ` : ''}

                return comp;
            }

            float WeDecodeValue(vec3 str){
                vec4 comp = WeDecodeComponent(str);
                bool isUV = Weget_isUV() > 0.0;
                return isUV ? length(comp.xy) : comp.x;
            }
            float WeDecodeValue(vec2 uv){
                bool isUV = Weget_isUV() > 0.0;

                bool isCR = Weget_isCR() > 0.0;
                if(isCR){
                    vec4 comp = WeDecodeComponent(uv);
                    float value = isUV ? length(comp.xy) : comp.x;
                    for(float i=0.025;i<1.0;i+=0.025){
                      vec4 comp2 = WeDecodeComponent(vec3(uv,i));
                      float value2 = isUV ? length(comp2.xy) : comp2.x;
                      if(value2 > value){
                        value = value2;
                      }
                    }
                    return value;
                }else{
                  vec4 comp = WeDecodeComponent(uv);
                  return isUV ? length(comp.xyz) : comp.x;
                }
            }
        `;

    if (isSampler3D) {
      let WeDecodeVal
      let textureValueFunc
      if (pixelFormat === Cesium.PixelFormat.ALPHA) {
        textureValueFunc = 'color.a'
      }
      else if (pixelFormat === Cesium.PixelFormat.RG) {
        textureValueFunc = 'color.rg'
      }
      else if (pixelFormat === Cesium.PixelFormat.RGB && pixelDatatype != Cesium.PixelDatatype.UNSIGNED_BYTE) {
        textureValueFunc = 'color.rgb'
      }
      else {
        textureValueFunc = 'color.r'
      }

      if (isUV || pixelDatatype == Cesium.PixelDatatype.FLOAT) {
        if (isUV && pixelDatatype == Cesium.PixelDatatype.UNSIGNED_BYTE) {
          WeDecodeVal = `
            vec4 WeDecodeVal(sampler3D tex,vec3 str){
                vec4 color = texture(tex,str);
                float u = color.x * 255.0 - 127.0 + color.y;
                float v = color.z * 255.0 - 127.0 + color.w;
                vec4 comp = vec4(u,v,0.0,0.0);
                return comp;
            }
            vec4 WeDecodeVal(sampler3D tex,vec2 uv){
                return WeDecodeVal(tex,vec3(uv,0.0));
            }`
        }
        else if (isUV && pixelDatatype == Cesium.PixelDatatype.UNSIGNED_SHORT) {
          WeDecodeVal = `
            vec4 WeDecodeVal(sampler3D tex,vec3 str){
                vec4 color = texture(tex,str);
                float u = (color.x - 0.5) * 65534.0;
                float v = (color.y - 0.5) * 65534.0;
                float w = (color.z - 0.5) * 65534.0;
                vec4 comp = vec4(u,v,w,0.0);
                return comp;
            }
            vec4 WeDecodeVal(sampler3D tex,vec2 uv){
                return WeDecodeVal(tex,vec3(uv,0.0));
            }`
        }
        else {
          WeDecodeVal = `
            vec4 WeDecodeVal(sampler3D tex,vec3 str){
                vec4 comp = texture(tex,str);
                return comp;
            }
            vec4 WeDecodeVal(sampler3D tex,vec2 uv){
                return WeDecodeVal(tex,vec3(uv,0.0));
            }`
        }
      } else {
        WeDecodeVal = `
                vec4 WeDecodeVal(sampler3D tex,vec3 str){
                    float offset = Weget_offset();
                    float scale = Weget_scale();
                    vec4 color = texture(tex,str);
                    float value = czm_valueTransform(offset,scale,${textureValueFunc});
                    vec3 nor = czm_octDecode(color.gb * 255.0);
                    return vec4(value,nor);
                  }
                  vec4 WeDecodeVal(sampler3D tex,vec2 uv){
                      float value = WeDecodeVal(tex,vec3(uv,0.0)).x;
                      return vec4(value);
                  }
                `
      }

      decodeShaderSource = `
                ${WeDecodeVal}
            `
    }
    else {
      let textureValueFunc;

      if (isUV) {
        if (pixelDatatype === Cesium.PixelDatatype.UNSIGNED_SHORT
          || pixelDatatype === Cesium.PixelDatatype.UNSIGNED_INT
        ) {
          textureValueFunc = `
                vec4 comp = color
           `
        } else if (pixelDatatype === Cesium.PixelDatatype.UNSIGNED_BYTE) {
          textureValueFunc = `
                    float u = color.x * 255.0 - 127.0 + color.y;
                    float v = color.z * 255.0 - 127.0 + color.w;
                    vec4 comp = vec4(u,v,0.0,0.0)
                    `
        } else {
          textureValueFunc = `
                    vec4 comp = color
                    `
        }
      } else {
        if (pixelFormat === Cesium.PixelFormat.ALPHA) {
          textureValueFunc = `
                    float offset = Weget_offset();
                    float scale = Weget_scale();
                    vec4 comp = vec4(czm_valueTransform(offset,scale,color.a));
                    `
        } else if (pixelFormat === Cesium.PixelFormat.R) {
          if (this.weUniform.Properties.scale !== 1.0
            || this.weUniform.Properties.offset !== 0
          ) {
            textureValueFunc = `
                    float offset = Weget_offset();
                    float scale = Weget_scale();
                    vec4 comp = vec4(czm_valueTransform(offset,scale,color.r));
                    `
          } else {
            textureValueFunc = 'vec4 comp = vec4(color.r)'
          }
        } else if (pixelFormat === Cesium.PixelFormat.RG) {
          textureValueFunc = 'vec4 comp = color'
        } else if (pixelFormat === Cesium.PixelFormat.RGB) {
          textureValueFunc = 'vec4 comp = color'
        } else {

          textureValueFunc = 'vec4 comp = color'
        }
      }

      decodeShaderSource = `
            vec4 WeDecodeVal(sampler2D tex, vec2 uv){
                vec4 color = texture(tex,uv);
                ${textureValueFunc};
                return comp;
            }
            vec4 WeDecodeVal(sampler2D tex, vec3 str){
                return WeDecodeVal(tex, str.xy);
            }
            `;
    }

    const decodeSource = `
        ${decodeShaderSource}
        ${WeDecodeValue}
        `
    return decodeSource
  }
}

export default WeDisplayValueDecoder
